package cn.fetosoft.woodpecker.core.jmeter.collector;

import cn.fetosoft.woodpecker.core.data.entity.TestResult;
import cn.fetosoft.woodpecker.core.data.service.TestResultService;
import cn.fetosoft.woodpecker.core.enums.ElementCategory;
import cn.fetosoft.woodpecker.core.event.SampleResultEvent;
import cn.fetosoft.woodpecker.core.util.Constant;
import cn.fetosoft.woodpecker.core.util.IpUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.assertions.AssertionResult;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.threads.JMeterContextService;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import java.util.HashMap;
import java.util.Map;

/**
 * @author guobingbing
 * @version 1.0
 * @wechat t_gbinb
 * @create 2021/6/23 16:26
 */
public class ResultCollectorDump extends ResultCollector {

	private static final Logger logger = LoggerFactory.getLogger(ResultCollectorDump.class);
	private ApplicationContext applicationContext;
	private TestResultService testResultService;

	public ResultCollectorDump(Summariser summer, ApplicationContext applicationContext){
		super(summer);
		this.applicationContext = applicationContext;
		testResultService = applicationContext.getBean(TestResultService.class);
	}

	@Override
	protected void sendToVisualizer(SampleResult r) {
		try {
			Sampler sampler = JMeterContextService.getContext().getCurrentSampler();

			TestResult testResult = this.covertResult(r, sampler);
			testResult.setParentId(Constant.ROOT_PARENT_ID);
			testResultService.insert(testResult);
			this.insertAssertion(r, testResult);

			this.insertChildren(testResult.getId(), r, sampler);
			SampleResultEvent event = new SampleResultEvent(testResult);
			event.setUserId(sampler.getPropertyAsString(Constant.USER_ID));
			this.applicationContext.publishEvent(event);
		} catch (Exception e) {
			logger.error("sendToVisualizer", e);
		}
	}

	/**
	 *
	 * @param r
	 * @return
	 */
	private TestResult covertResult(SampleResult r, Sampler sampler) throws Exception{
		TestResult result = new TestResult();
		result.setId(new ObjectId().toString());
		result.setName(r.getSampleLabel());
		result.setThreadId(r.getThreadId());
		result.setPlanId(sampler.getPropertyAsString(Constant.PLAN_ID));
		result.setElementId(sampler.getPropertyAsString(Constant.ELEMENT_ID));
		result.setTestId(sampler.getPropertyAsString(Constant.TEST_ID));
		result.setUserId(sampler.getPropertyAsString(Constant.USER_ID));
		result.setCategory(sampler.getPropertyAsString(Constant.CATEGORY));
		result.setResponseCode(r.getResponseCode());
		result.setSamplerData(r.getSamplerData());
		result.setThreadName(r.getThreadName());
		result.setRequestHeaders(r.getRequestHeaders());
		result.setResponseMessage(r.getResponseMessage());
		result.setResponseHeaders(r.getResponseHeaders());
		result.setResponseData(r.getResponseDataAsString());
		result.setTimeStamp(r.getTimeStamp());
		result.setStartTime(r.getStartTime());
		result.setEndTime(r.getEndTime());
		result.setIdleTime(r.getIdleTime());
		result.setElapsedTime(r.getTime());
		result.setLatency(r.getLatency());
		result.setConnectTime(r.getConnectTime());
		result.setStopThread(r.isStopThread());
		result.setStopTest(r.isStopTest());
		result.setStopTestNow(r.isStopTestNow());
		result.setSampleCount(r.getSampleCount());
		result.setBytes(r.getBytesAsLong());
		result.setHeadersSize(r.getHeadersSize());
		result.setBodySize(r.getBodySizeAsLong());
		result.setGroupThreads(r.getGroupThreads());
		result.setAllThreads(r.getAllThreads());
		result.setSentBytes(r.getSentBytes());
		result.setDataType(r.getDataType());
		result.setContentType(r.getContentType());
		result.setErrorCount(r.getErrorCount());
		result.setIp(IpUtil.getSingleLocalIP());
		return result;
	}

	private void insertChildren(String parentId, SampleResult parent, Sampler sampler) throws Exception{
		SampleResult[] children = parent.getSubResults();
		if(children!=null && children.length>0){
			for(SampleResult c : children) {
				TestResult child = this.covertResult(c, sampler);
				child.setParentId(parentId);
				testResultService.insert(child);
				this.insertChildren(child.getId(), c, sampler);
			}
		}
	}

	private void insertAssertion(SampleResult result, TestResult parent) throws Exception{
		AssertionResult[] asserts = result.getAssertionResults();
		for (AssertionResult ar : asserts){
			TestResult testResult = new TestResult();
			testResult.setId(new ObjectId().toString());
			testResult.setThreadId(result.getThreadId());
			testResult.setParentId(parent.getId());
			testResult.setName(ar.getName());
			testResult.setPlanId(parent.getPlanId());
			testResult.setElementId(ar.getElementId());
			testResult.setTestId(parent.getTestId());
			testResult.setUserId(parent.getUserId());
			testResult.setCategory(ar.getCategory());

			testResult.setAssertionError(ar.isError());
			testResult.setAssertionFailure(ar.isFailure());
			if(ar.isError() || ar.isFailure()){
				testResult.setErrorCount(1);
			}
			testResult.setAssertionMessage(ar.getFailureMessage());
			testResult.setIp(IpUtil.getSingleLocalIP());
			testResultService.insert(testResult);
		}
	}
}
